import java.util.ArrayList;
import java.util.Arrays;


/**
 * @author Jarvan
 */
public class Expression {

    /**
     * The content of this expression
     */
    private String infix;


    /**
     * This is the default expression.
     */
    public Expression() {
        infix = "9+(3-1)*3+10/2";
    }

    /**
     * Init the infix with para infix.
     *
     * @param infix infix expression.
     */
    public Expression(String infix) {
        this.infix = infix;
    }

    /**
     * Use util Class(Write by myself) to change infix expression to postfix expression.
     *
     * @return postfix.
     */
    public ArrayList<String> infixToPostfix() {
        //init stack
        GenericStack<Character> myStack = new GenericStack<Character>();
        //postfix.
        StringBuilder postfix = new StringBuilder();
        int length = infix.length();
        for (int i = 0; i < length; i++) {
            char tempChar;
            char charAt = infix.charAt(i);
            switch (charAt) {
                //左括号直接入栈，不用过多解释
                case '(':
                    myStack.push(charAt);
                    break;
                //如果遇到 +-，低级会导致一次出栈.
                case '+':
                case '-':
                    //出栈
                    while (!myStack.isEmpty()) {
                        tempChar =  myStack.pop();
                        if (tempChar == '(') {
                            myStack.push(tempChar);
                            break;
                        }
                        postfix.append(" ").append(tempChar);
                    }
                    myStack.push(charAt);
                    break;
                case '*':
                case '/':
                    while (!myStack.isEmpty()) {
                        tempChar =  myStack.pop();
                        if (tempChar == '(' || tempChar == '+' || tempChar == '-') {
                            myStack.push(tempChar);
                            break;
                        }
                        postfix.append(" ").append(tempChar);
                    }
                    myStack.push(charAt);
                    break;
                case ')':
                    while (!myStack.isEmpty()) {
                        tempChar =  myStack.pop();
                        if (tempChar != '(') {
                            postfix.append(" ").append(tempChar);
                        } else {
                            break;
                        }
                    }
                    break;
                default:
                    postfix.append(" ").append(charAt);
                    //if length enough
                    if (i < length - 1) {
                        int j = i + 1;
                        char nextNumber = infix.charAt(j);
                        while ((nextNumber + "").matches("^[0-9]*") && j < length) {
                            postfix.append(nextNumber);
                            nextNumber = infix.charAt(++j);
                        }
                        i = j - 1;
                    }
                    break;


            }
        }
        while (!myStack.isEmpty()) {
            postfix.append(" ").append(myStack.pop());
        }
        String[] strings = postfix.toString().trim().split(" ");
        return new ArrayList<>(Arrays.asList(strings));
    }


    /**
     * Use util Class(Write by myself) to get the value of the infix.
     *
     * @return value of the infix.
     */
    public int evaluate() {
        GenericStack<Character> myStack = new GenericStack<Character>();
        String[] items = infixToPostfix().toArray(new String[0]);
        int length = items.length;
        for (int i = 0; i < length; i++) {
            String tempItem = items[i];
            switch (tempItem) {
                case "+":
                    char first =  myStack.pop();
                    char second =  myStack.pop();
                    int result = (int) second + (int) first;
                    myStack.push((char) result);
                    break;
                case "-":
                    char first2 =  myStack.pop();
                    char second2 =  myStack.pop();
                    int result2 = (int) second2 - (int) first2;
                    myStack.push((char) result2);
                    break;
                case "*":
                    char first3 = myStack.pop();
                    char second3 = myStack.pop();
                    int result3 = (int) second3 * (int) first3;
                    myStack.push((char) result3);
                    break;
                case "/":
                    char first4 = myStack.pop();
                    char second4 = myStack.pop();
                    int result4 = (int) second4 / (int) first4;
                    myStack.push((char) result4);
                    break;
                //if is number.
                default:
                    int charInt = Integer.parseInt(tempItem);
                    myStack.push((char) charInt);
                    break;
            }
        }
        return (int) myStack.pop();
    }

    //Other methods
    //Helper methods
}
